library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.4.4 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(gganimate)
library(here) # for specifying directory location
## here() starts at /Users/jeanclipperton/Desktop/animation
theme_set(theme_minimal())
Import data
freedom <- read_csv(
file = here("data", "freedom.csv"),
# NA values are recorded as '-'
na = "-"
)
## Rows: 205 Columns: 94
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (32): country, status_1990, status_1991, status_1992, status_1993, statu...
## dbl (62): pr_1990, cl_1990, pr_1991, cl_1991, pr_1992, cl_1992, pr_1993, cl_...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
freedom
## # A tibble: 205 × 94
## country pr_1990 cl_1990 status_1990 pr_1991 cl_1991 status_1991 pr_1992
## <chr> <dbl> <dbl> <chr> <dbl> <dbl> <chr> <dbl>
## 1 Afghanistan 7 7 NF 7 7 NF 6
## 2 Albania 7 6 NF 4 4 PF 4
## 3 Algeria 4 4 PF 4 4 PF 7
## 4 Andorra NA NA <NA> NA NA <NA> NA
## 5 Angola 7 7 NF 6 4 PF 6
## 6 Antigua and … 3 2 F 3 3 PF 3
## 7 Argentina 1 3 F 1 3 F 2
## 8 Armenia NA NA <NA> 5 5 PF 4
## 9 Australia 1 1 F 1 1 F 1
## 10 Austria 1 1 F 1 1 F 1
## # ℹ 195 more rows
## # ℹ 86 more variables: cl_1992 <dbl>, status_1992 <chr>, pr_1993 <dbl>,
## # cl_1993 <dbl>, status_1993 <chr>, pr_1994 <dbl>, cl_1994 <dbl>,
## # status_1994 <chr>, pr_1995 <dbl>, cl_1995 <dbl>, status_1995 <chr>,
## # pr_1996 <dbl>, cl_1996 <dbl>, status_1996 <chr>, pr_1997 <dbl>,
## # cl_1997 <dbl>, status_1997 <chr>, pr_1998 <dbl>, cl_1998 <dbl>,
## # status_1998 <chr>, pr_1999 <dbl>, cl_1999 <dbl>, status_1999 <chr>, …
- Data is in a wide format
pr_* - political rights, scores 1-7 (1 highest degree
of freedom, 7 the lowest)
cl_* - civil liberties, scores 1-7 (1 highest degree of
freedom, 7 the lowest)
status_* - freedom status (Free, Partly Free, and Not
Free)
Calculate the top fifteen countries whose civil liberties scores
have varied the most
freedom_to_plot <- freedom %>%
# calculate rowwise standard deviations (one row per country)
rowwise() %>%
mutate(sd = sd(c_across(contains("cl_")), na.rm = TRUE)) %>%
ungroup() %>%
# find the 15 countries with the highest standard deviations
relocate(country, sd) %>%
slice_max(order_by = sd, n = 15) %>%
# only keep countries with complete observations - necessary for future plotting
drop_na()
freedom_to_plot
## # A tibble: 11 × 95
## country sd pr_1990 cl_1990 status_1990 pr_1991 cl_1991 status_1991 pr_1992
## <chr> <dbl> <dbl> <dbl> <chr> <dbl> <dbl> <chr> <dbl>
## 1 The Ga… 1.28 2 2 F 2 2 F 1
## 2 Sierra… 1.22 6 5 PF 6 5 PF 7
## 3 Centra… 1.12 6 5 NF 6 5 PF 6
## 4 Ghana 1.12 6 5 NF 6 6 NF 5
## 5 Kenya 1.11 6 6 NF 6 6 NF 4
## 6 Liberia 1.09 7 7 NF 7 6 NF 7
## 7 Bhutan 1.02 6 5 PF 6 5 PF 7
## 8 Malawi 1.02 7 6 NF 7 6 NF 6
## 9 Turkey 1.01 2 4 PF 2 4 PF 2
## 10 Venezu… 0.990 1 3 F 1 3 F 3
## 11 Tanzan… 0.948 6 5 NF 6 5 NF 6
## # ℹ 86 more variables: cl_1992 <dbl>, status_1992 <chr>, pr_1993 <dbl>,
## # cl_1993 <dbl>, status_1993 <chr>, pr_1994 <dbl>, cl_1994 <dbl>,
## # status_1994 <chr>, pr_1995 <dbl>, cl_1995 <dbl>, status_1995 <chr>,
## # pr_1996 <dbl>, cl_1996 <dbl>, status_1996 <chr>, pr_1997 <dbl>,
## # cl_1997 <dbl>, status_1997 <chr>, pr_1998 <dbl>, cl_1998 <dbl>,
## # status_1998 <chr>, pr_1999 <dbl>, cl_1999 <dbl>, status_1999 <chr>,
## # pr_2000 <dbl>, cl_2000 <dbl>, status_2000 <chr>, pr_2001 <dbl>, …
# calculate position rankings rather than raw scores
freedom_ranked <- freedom_to_plot %>%
# only keep columns with civil liberties scores
select(country, contains("cl_")) %>%
# wrangle the data to a long format
pivot_longer(
cols = -country,
names_to = "year",
values_to = "civil_liberty",
names_prefix = "cl_",
names_transform = list(year = as.numeric)
) %>%
# calculate rank within year - larger is worse, so reverse in the ranking
group_by(year) %>%
mutate(rank_in_year = rank(-civil_liberty, ties.method = "first")) %>%
ungroup() %>%
# highlight Turkey
mutate(is_turkey = if_else(country == "Turkey", TRUE, FALSE))
Faceted plot
freedom_faceted_plot <- freedom_ranked %>%
# civil liberty vs freedom rank
ggplot(aes(x = civil_liberty, y = factor(rank_in_year), fill = is_turkey)) +
geom_col(show.legend = FALSE) +
# change the color palette for emphasis of Turkey
scale_fill_manual(values = c("gray", "red")) +
# facet by year
facet_wrap(vars(year)) +
# create explicit labels for civil liberties score,
# leaving room for country text labels
scale_x_continuous(
limits = c(-5, 7),
breaks = 1:7
) +
geom_text(
hjust = "right",
aes(label = country),
x = -1
) +
# remove extraneous theme/label components
theme(
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
axis.text.y = element_blank()
) +
labs(x = NULL, y = NULL)
freedom_faceted_plot

Animated plot
freedom_bar_race <- freedom_faceted_plot +
# remove faceting
facet_null() +
# label the current year in the top corner of the plot
geom_text(
x = 5, y = 11,
hjust = "left",
aes(label = as.character(year)),
size = 10
) +
# define group structure for transitions
aes(group = country) +
# temporal transition - ensure integer value for labeling
transition_time(as.integer(year)) +
labs(
title = "Civil liberties rating, {frame_time}",
subtitle = "1: Highest degree of freedom - 7: Lowest degree of freedom"
)
# basic transition
animate(freedom_bar_race, nframes = 30, fps = 2)

# smoother transition
animate(freedom_bar_race, nframes = 300, fps = 10, start_pause = 10, end_pause = 10)
